﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace GameEngine
{
    public static class Functions
    {

        #region Graphics

        /// <summary>
        /// Sets the resolution of the game, if supported.
        /// </summary>
        /// <param name="iWidth">Desired screen width.</param>
        /// <param name="iHeight">Desired screen height.</param>
        /// <param name="bFullScreen">True if you wish to go to Full Screen, false for Windowed Mode.</param>
        public static void SetDisplayMode(ref GraphicsDeviceManager graphics, int iWidth, int iHeight, bool bFullScreen)
        {
            if (IsSupportedDisplayMode(iWidth, iHeight, bFullScreen))
            {
                graphics.PreferredBackBufferWidth = iWidth;
                graphics.PreferredBackBufferHeight = iHeight;
                graphics.IsFullScreen = bFullScreen;
                graphics.ApplyChanges();
            }
        }

        /// <summary>
        /// Control if the requested resolution is supported.  Itterates through the display
        /// capabilities of the default graphics adapter to determine if the graphics adapter supports the
        /// requested resolution. If so, returns true. If not, returns false.
        /// </summary>
        /// <param name="iWidth">Desired screen width.</param>
        /// <param name="iHeight">Desired screen height.</param>
        /// <param name="bFullScreen">True if you wish to go to Full Screen, false for Windowed Mode.</param>
        private static bool IsSupportedDisplayMode(int iWidth, int iHeight, bool bFullScreen)
        {
            if (bFullScreen)
            {
                // If we are using full screen mode, we should check to make sure that the display
                // adapter can handle the video mode we are trying to set.  To do this, we will
                // iterate thorugh the display modes supported by the adapter and check them against
                // the mode we want to set.
                foreach (DisplayMode dm in GraphicsAdapter.DefaultAdapter.SupportedDisplayModes)
                {
                    // Check the width and height of each mode against the passed values
                    if ((dm.Width == iWidth) && (dm.Height == iHeight))
                    {
                        return true;
                    }
                }
                return false;
            }
            else
            {
                // If we aren't using a full screen mode, the height and width of the window can
                // be set to anything equal to or smaller than the actual screen size.
                return ((iWidth <= GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width)
                    && (iHeight <= GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height));
            }
        }

        #endregion

        #region Content Handlers

        /// <summary>
        /// Method that handles the loading of textures and controling that the item in the path is correct.
        /// If path is wrong it returns a generic File-not-found image.
        /// </summary>
        /// <param name="content">Target content loader</param>
        /// <param name="filePath">the filepath</param>
        /// <returns>Loaded texture or File not found Image</returns>
        public static Texture2D TextureContentLoader(ContentManager content, String filePath)
        {
            Texture2D texture2D;
            try
            {
                texture2D = content.Load<Texture2D>(filePath);
            }
            catch (ContentLoadException e)
            {
                if (e.Source != null)
                    ODS(e.Source + ", Path[ " + filePath + " ] was not found");

                    texture2D = content.Load<Texture2D>(@"Texture\FileNotFound");
            }


            return texture2D;
        }

        #endregion

        #region debugFunctions

        /// <summary>
        /// Used for debug purposes, outputs errormessage 
        /// </summary>
        /// <param name="message">Errormessage</param>
        public static void ODS(string message)
        {
            System.Diagnostics.Debug.WriteLine(String.Format("{0}   {1}", DateTime.Now.ToString("hh:mm:ss.ff"), message));
        }

        #endregion

        #region Collision Handling
        /// <summary>
        ///This method checks to see if the Sprite is going to move into an area that does
        ///not contain all Gray pixels. If the move amount would cause a movement into a non-gray
        ///pixel, then a collision has occurred.
        /// </summary>
        /// <param name="newPosition"></param>
        /// <returns>true if a collision occurred</returns>
        public static bool CollisionOccurred(GraphicsDevice GD, RenderTarget2D mTrackRender, SpriteBatch spriteBatch, Rectangle CollisionBox, Texture2D collisionLayer)
        {
            //Calculate the Position of the Car and create the collision Texture. This texture will contain
            //all of the pixels that are directly underneath the sprite currently on the Track image.
            Texture2D aCollisionCheck = CreateCollisionTexture(GD, mTrackRender, spriteBatch, CollisionBox, collisionLayer);

            //Use GetData to fill in an array with all of the Colors of the Pixels in the area of the Collision Texture
            int aPixels = CollisionBox.Width * CollisionBox.Height;

            Color[] myColors = new Color[aPixels];

            aCollisionCheck.GetData<Color>(0,
                new Rectangle(
                    (int)(aCollisionCheck.Width / 2 - CollisionBox.Width / 2),
                    (int)(aCollisionCheck.Height / 2 - CollisionBox.Height / 2),
                    CollisionBox.Width, CollisionBox.Height), myColors, 0, aPixels);


            //Cycle through all of the colors in the Array and see if any of them
            //are not Gray. If one of them isn't Gray a Collision has occurred
            foreach (Color aColor in myColors)
                if (aColor != Color.Gray) return true;

            return false;
        }


        private static Texture2D CreateCollisionTexture(GraphicsDevice GD, RenderTarget2D mTrackRender, SpriteBatch spriteBatch, Rectangle CollisionBox, Texture2D collisionLayer)
        {

            GD.SetRenderTarget(mTrackRender);
            GD.Clear(ClearOptions.Target, Color.Red, 0, 0);
            spriteBatch.Begin();

            int collisonMargin = 50;

            spriteBatch.Draw(
                collisionLayer,
                new Rectangle(0, 0, CollisionBox.Width + collisonMargin, CollisionBox.Height + collisonMargin),
                new Rectangle((int)(CollisionBox.X - collisonMargin / 2), (int)(CollisionBox.Y - collisonMargin / 2),
                    CollisionBox.Width + collisonMargin, CollisionBox.Height + collisonMargin),
                Color.White);

            spriteBatch.End();

            GD.SetRenderTarget(null);

            return mTrackRender;
        }
        #endregion

    }
}
